package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

const tmpFilePath string = "/tmp/data_xiao_bai"

func main() {
	initFile()

	// Go 团队鼓励使用更底层的 os.ReadFile 函数来代替 ioutil.ReadFile
	// 此方法是 读取整个文件内容到内存
	dat, err := os.ReadFile(tmpFilePath)
	check(err)
	fmt.Print(string(dat))

	// 如果想控制怎么读、读取哪一部分。则使用 os.Open 打开一个文件获取一个 os.File 值
	f, err := os.Open(tmpFilePath)
	defer func() {
		// 任务结束后要关闭这个文件
		closeErr := f.Close()
		check(closeErr)

		removeFile()
		fmt.Println("file is closed")
	}()
	check(err)

	// 从文件开始位置读取一些字节。这里最多读取 5 个字节，并且这也是我们实际读取的字节数
	b1 := make([]byte, 5)
	n1, err := f.Read(b1)
	check(err)
	fmt.Printf("read %d bytes: %s\n", n1, string(b1))

	// 也可以使用 Seek， 从文件中的已知位置开始读取。
	o2, err := f.Seek(6, 0)
	check(err)
	b2 := make([]byte, 2)
	n2, err := f.Read(b2)
	check(err)
	fmt.Printf("read %d bytes @ %d: %s\n", n2, o2, string(b2))

	// io 包提供了一些可以帮助我们进行文件读取的函数。例如，上面的读取可以使用 ReadAtLeast 得到一个更健壮的实现。
	o3, err := f.Seek(6, 0)
	check(err)
	b3 := make([]byte, 2)
	n3, err := io.ReadAtLeast(f, b3, 2)
	check(err)
	fmt.Printf("read %d bytes @ %d: %s\n", n3, o3, string(b3))

	// 没有内置的回转支持，但可以使用 Seek(0, 0) 实现。
	_, err = f.Seek(0, 0)
	check(err)

	// bufio 包实现了带缓冲的读取，这不仅对有很多小的读取操作的能提升性能，也提供了很多附加的读取函数。
	r4 := bufio.NewReader(f)
	b4, err := r4.Peek(5)
	check(err)
	fmt.Printf("read 5 bytes: %s\n", string(b4))
}

// 读取文件需要经常进行错误检查，这个帮助方法可以精简下面的错误检查过程。
func check(e error) {
	if e != nil {
		panic(e)
	}
}

func initFile() {
	d1 := []byte("hello\ngo\n")
	err := os.WriteFile(tmpFilePath, d1, 0644)
	check(err)
}

func removeFile() {
	err := os.Remove(tmpFilePath)
	if err != nil {
		return
	}
}
